package com.fansl.allround.common.example.thread;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import com.fansl.allround.common.core.mybatis.DataScope;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author fansl
 * @Description: 创建线程池的例子
 * @date 2019/7/8 14:09
 */
public class ThreadExample {
    /**
     * 使用继承Thread类实现方式
     * 1.创建一个线程类，继承Thread类，重写run方法
     * 2.实例化创建的线程类
     * 3.调用start方法，启动线程
     */
    public static void startThread(){
        System.out.println("-------多线程创建开始-------");
        //1.创建一个线程
        CreateThread createThread = new CreateThread();
        //2.开始执行线程，调用start方法开启线程
        System.out.println("-------多线程创建启动-------");
        createThread.start();
        //注意：使用开启多线程后，代码不会从上往下顺序执行，而是有一条新的执行分支
        System.out.println("-------多线程创建结束-------");
    }

    /**
     * 实现Runnable接口的方式
     * 1.创建一个线程类，实现Runnable接口。实现run方法
     * 2，实例化创建线程类
     * 3.执行new Thread(实例化创建的线程类).start,启动线程
     */
    public static void startRunnableThread(){
        System.out.println("-------多线程创建开始-------");
        //1.创建一个线程
        CreateRunnableThread runnableThread = new CreateRunnableThread();
        //2.开始执行线程，调用start方法开启线程
        System.out.println("-------多线程创建启动-------");
        Thread thread = new Thread(runnableThread);
        thread.start();
        //注意：使用开启多线程后，代码不会从上往下顺序执行，而是有一条新的执行分支
        System.out.println("-------多线程创建结束-------");
    }
    /**
     * 实现Callable接口的方式
     * 1.创建一个线程类，实现Callable接口。实现call方法
     * 2.实例化创建线程类
     * 3.实例化FutureTask(实例化创建线程类)
     * 4.执行new Thread(FutureTask).start,启动线程
     */
    public static void startCallableThread(){
        System.out.println("-------多线程创建开始-------");
        //1.创建一个线程
        CreateCallableThread callableThread = new CreateCallableThread();
        //2.开始执行线程，调用start方法开启线程
        System.out.println("-------多线程创建启动-------");
        FutureTask<String> futureTask = new FutureTask<String>(callableThread);
        Thread thread = new Thread(futureTask);
        thread.start();
        try {
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //注意：使用开启多线程后，代码不会从上往下顺序执行，而是有一条新的执行分支
        System.out.println("-------多线程创建结束-------");
    }

    /**
     * 线程池
     */
    public static void threadPoolExecutor(){
        Runnable runnable = () -> {
            try {
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName() + " run");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        //可以看到每个任务都是是直接启动一个核心线程来执行任务，一共创建了6个线程，不会放入队列中。8秒后线程池还是6个线程，核心线程默认情况下不会被回收，不收超时时间限制。
//        ThreadPoolExecutor executor =
//                new ThreadPoolExecutor(6,10,5,TimeUnit.SECONDS,new SynchronousQueue<>());
        //当任务数超过核心线程数时，会将超出的任务放在队列中，只会创建3个线程重复利用。
//        ThreadPoolExecutor executor =
//                new ThreadPoolExecutor(3,6,5,TimeUnit.SECONDS,new LinkedBlockingQueue<>());
        //当队列是SynchronousQueue时，超出核心线程的任务会创建新的线程来执行，看到一共有6个线程。但是这些线程是费核心线程，收超时时间限制，在任务完成后限制超过5秒就会被回收。所以最后看到线程池还是只有三个线程。
//        ThreadPoolExecutor executor =
//            new ThreadPoolExecutor(3,6,5,TimeUnit.SECONDS,new SynchronousQueue<>());
        //LinkedBlockingDeque根本不受最大线程数影响。但是当LinkedBlockingDeque有大小限制时就会受最大线程数影响了
//        ThreadPoolExecutor executor =
//                new ThreadPoolExecutor(3,4,5,TimeUnit.SECONDS,new LinkedBlockingDeque<>());
        //首先为三个任务开启了三个核心线程1，2，3，然后第四个任务和第五个任务加入到队列中，第六个任务因为队列满了，就直接创建一个新线程4，这是一共有四个线程，没有超过最大线程数。8秒后，非核心线程收超时时间影响回收了，因此线程池只剩3个线程了。
//        ThreadPoolExecutor executor =
//                new ThreadPoolExecutor(3,4,5,TimeUnit.SECONDS,new LinkedBlockingDeque<>(2));
        //直接出错在第6个execute方法上。因为核心线程是3个，当加入第四个任务的时候，就把第四个放在队列中。加入第五个任务时，因为队列满了，就创建新线程执行，创建了线程4。当加入第六个线程时，也会尝试创建线程，但是因为已经达到了线程池最大线程数，所以直接抛异常了。
//        ThreadPoolExecutor executor =
//                new ThreadPoolExecutor(3,4,5,TimeUnit.SECONDS,new LinkedBlockingDeque<>(1));
        //这次在添加第五个任务时就报错了，因为SynchronousQueue根本不保存任务，收到一个任务就去创建新线程。所以第五个就会抛异常了。
        ThreadPoolExecutor executor =
                new ThreadPoolExecutor(3,4,5,TimeUnit.SECONDS,new SynchronousQueue<>());
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        System.out.println("---先开三个---");
        System.out.println("核心线程数" + executor.getCorePoolSize());
        System.out.println("线程池数" + executor.getPoolSize());
        System.out.println("队列任务数" + executor.getQueue().size());
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        System.out.println("---再开三个---");
        System.out.println("核心线程数" + executor.getCorePoolSize());
        System.out.println("线程池数" + executor.getPoolSize());
        System.out.println("队列任务数" + executor.getQueue().size());
        try {
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("----8秒之后----");
        System.out.println("核心线程数" + executor.getCorePoolSize());
        System.out.println("线程池数" + executor.getPoolSize());
        System.out.println("队列任务数" + executor.getQueue().size());
    }
    public static void whenComplete() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
            if(new Random().nextInt()%2>=0) {
                int i = 12/0;
            }
            System.out.println("run end ...");
        });

        future.whenComplete(new BiConsumer<Void, Throwable>() {
            @Override
            public void accept(Void t, Throwable action) {
                System.out.println("执行完成！");
            }

        });
        future.exceptionally(new Function<Throwable, Void>() {
            @Override
            public Void apply(Throwable t) {
                System.out.println("执行失败！"+t.getMessage());
                return null;
            }
        });

        TimeUnit.SECONDS.sleep(2);
    }
    public static void main(String[] args) {
        //startThread();
        //startRunnableThread();
        //startCallableThread();
        //threadPoolExecutor();
//        Integer sorce = 10;
//        Double sameScore = 10.0;
//        System.out.println(sameScore.equals(sorce.doubleValue()));
//        double initScore = System.currentTimeMillis() / 10000000000000d;
//        Double num= 10.9562651214829;
//        System.out.println(num.longValue());
//        ThreadPoolExecutor executor1 =
//                new ThreadPoolExecutor(2, 4, 5, TimeUnit.SECONDS,
//                        new ArrayBlockingQueue<>(4),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
//        ScheduledThreadPoolExecutor  scheduled = new ScheduledThreadPoolExecutor(2);
//        //0表示首次执行任务的延迟时间，40表示每次执行任务的间隔时间，TimeUnit.MILLISECONDS执行的时间间隔数值单位
//        scheduled.scheduleAtFixedRate(() -> {
//            System.out.println(Thread.currentThread().getName()+"-time:"+System.currentTimeMillis());
//            try {
//                TimeUnit.SECONDS.sleep(3);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }, 10, 2, TimeUnit.SECONDS);
//        for (int i = 0; i < 10; i++) {
//            AtomicInteger threadNum = new AtomicInteger(i+1);
//            System.out.println("创建Thread"+threadNum.get());
//            CompletableFuture.runAsync(()->{
//                System.out.println(Thread.currentThread().getName()+"-Thread:"+threadNum.get()+"-核心线程数" + executor1.getCorePoolSize());
//                System.out.println(Thread.currentThread().getName()+"-Thread:"+threadNum.get()+"-线程池数" + executor1.getPoolSize());
//                System.out.println(Thread.currentThread().getName()+"-Thread:"+threadNum.get()+"-队列任务数" + executor1.getQueue().size());
//            },executor1);
//        }
//        System.out.println("isShutdown:"+executor1.isShutdown());
//        executor1.shutdown();
//        System.out.println("isShutdown:"+executor1.isShutdown());
//        try {
//            whenComplete();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        List<DataScope> list = new ArrayList<>();
        System.out.println(list.stream()
                .collect(Collectors.groupingBy(DataScope::getScopeName)));
        LocalDate updateDate = LocalDateTime.ofInstant(new Date().toInstant(),ZoneId.systemDefault()).toLocalDate();
        System.out.println(updateDate);
        System.out.println(LocalDate.now());
        if (updateDate.isEqual(LocalDate.now())){
            System.out.println(true);
        }
        LocalDate localDate1 = LocalDate.of(2019,9,20);
        LocalDate localDate2 = LocalDate.of(2019,9,10);
        LocalDate localDate3 = LocalDate.of(2019,8,10);
        Period period1 = Period.between(localDate1,localDate2);
        Period period2 = Period.between(localDate2,localDate1);
        Period period3 = Period.between(localDate2,localDate3);
        System.out.println(period1.getDays());
        System.out.println(period2.getDays());
        System.out.println(period3.getDays());
        System.out.println(localDate2.toEpochDay()-localDate3.toEpochDay());
        long days = 10;
        System.out.println(10==days);
//        Path file = Paths.get("D:/沉默王二.txt");
//        try (BufferedWriter bufferedWriter = Files.newBufferedWriter(file,StandardCharsets.UTF_8)){
//            bufferedWriter.write("一次有趣的试验");
//            bufferedWriter.write("\n");
//            bufferedWriter.write("涨知识了");
//            bufferedWriter.write("!");
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        try (BufferedReader bufferedReader = Files.newBufferedReader(file, StandardCharsets.UTF_8)){
//            String line;
//            while ((line=bufferedReader.readLine())!=null){
//                System.out.println(line);
//            }
//        }catch (IOException e){
//            e.printStackTrace();
//        }
//        List<String> uuids = new ArrayList<>();
//        for (int i = 0;i<10;i++){
//            try {
//                CompletableFuture.supplyAsync(()-> {
//                    System.out.println("走这了1");
//                    return UUID.randomUUID().toString();
//                }).whenComplete((result, exception)->{
//                    System.out.println("走这了2");
//                    System.out.println(result);
//                    if (null == exception) {
//                        System.out.println("走这了3");
//                        uuids.add(result);
//                    }
//                });
//            }catch (Exception e){
//                e.printStackTrace();
//            }
//
//        }
//        System.out.println(uuids);
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // long running task
            return "task result";
        });

        future.whenComplete((result, exception) -> {
            if (null == exception) {
                System.out.println("result from previous task: " + result);
            }
        });
    }
}
